#ifndef _AUTH_HPP_
#define _AUTH_HPP_

#include <dlcom/cominc.h>


#define BUS_PRODUCER_VERSION	10
#define BUS_CONSUMER_VERSION	10

typedef struct _StringPtr {

	unsigned int len;
	char* data;

} StringPtr;



#define U_OFFSET 0
#define N_OFFSET 1
#define T_OFFSET 2
#define V_OFFSET 3
#define S_OFFSET 4
#define A_OFFSET 5
#define M_OFFSET 7
#define O_OFFSET 8



typedef struct _BusProtocol {

	unsigned int u;	//uid
	unsigned int n;	//netmask
	unsigned int t;	//type
	unsigned int v;	//ver
	unsigned int s;	//seq
	unsigned int a;	//ack
	unsigned int m;	//msg
	unsigned int o;	//opt

} BusProtocol;


typedef struct _Connect_Protocol {

	BusProtocol bus;
	StringPtr	str;

} Connect_Protocol;


typedef struct {

	BusProtocol bus;
	StringPtr	str;

} Package_Protocol;


#define BUS_PROTOCOL_HEAD_LEN	(sizeof(BusProtocol))
#define UINT_COUNT_SIZE(x)		(sizeof(unsigned int) * x)

#define BUS_OP_CONNECTED	1000
#define BUS_OP_CONNCET		1001

#define BUS_CONSUMER_HELLO	1000
#define BUS_PRODUCER_HELLO	2000
#define BUS_BROKER_HELLO	3000

#define BUS_ACK_VALUE		9
#define BUS_SEQ_VALUE		9
#define BUS_NULL_VALUE		0

#define BUS_OP_BASE			0
#define	BUS_OP_SEND_HEAD	BUS_OP_BASE + 2
#define	BUS_OP_SEND			BUS_OP_BASE + 3
#define BUS_OP_RECV_HEAD	BUS_OP_BASE + 4	
#define BUS_OP_RECV			BUS_OP_BASE + 5	

//comsumer + producer
#define BUS_OP_SEND_SEQ		BUS_OP_BASE + 100
#define BUS_OP_RECV_SEQ_ACK	BUS_OP_BASE + 101
#define BUS_OP_SEND_ACK		BUS_OP_BASE + 102

//broker
#define BUS_OP_RECV_SEQ		BUS_OP_BASE + 201
#define BUS_OP_SEND_SEQ_ACK	BUS_OP_BASE + 203
#define BUS_OP_RECV_ACK		BUS_OP_BASE + 202


static_inline int GetUInt(unsigned char* data, unsigned int* nVal)
{
	size_t nOffset(0);
	unsigned int a = (unsigned char)data[nOffset++];
	unsigned int b = (unsigned char)data[nOffset++];
	unsigned int c = (unsigned char)data[nOffset++];
	unsigned int d = (unsigned char)data[nOffset++];
	a = a << 24;
	a |= b << 16;
	a |= c << 8;
	a |= d;
	*nVal = a;

	return S_SUCCESS;
}

static_inline int SetUInt(unsigned char* data, unsigned int i)
{
	unsigned int b = i;
	size_t nOffset(0);
	data[nOffset++] = (unsigned char)(0xFF & (b >> 24));
	data[nOffset++] = (unsigned char)(0xFF & (b >> 16));
	data[nOffset++] = (unsigned char)(0xFF & (b >> 8));
	data[nOffset++] = (unsigned char)(0xFF & (b));

	return S_SUCCESS;
}


static_inline HRESULT IsConnect(Connect_Protocol* con) {

	rc_assert(con != NULL, E_FAIL)
	return con->bus.o == BUS_OP_CONNECTED ? S_OK : E_FAIL;
}


static_inline HRESULT BusProtocol_Init(BusProtocol* bus) {

	rc_assert(bus != NULL, E_FAIL)
	s_memset(bus, 0, BUS_PROTOCOL_HEAD_LEN);
	return S_OK;
}



static_inline HRESULT BusProtocol_Set_Ack(BusProtocol* bus, unsigned int value) {
	rc_assert(bus != NULL, E_FAIL)

	bus->a = value;
	return S_OK;
}

static_inline HRESULT BusProtocol_Set_Seq(BusProtocol* bus, unsigned int value) {
	rc_assert(bus != NULL, E_FAIL)

	bus->s = value;
	return S_OK;
}


static_inline HRESULT BusProtocol_Set(unsigned char* data, BusProtocol* bus) {
	
	rc_assert(data != NULL, E_FAIL)
	rc_assert(bus != NULL, E_FAIL)

	SetUInt(data + UINT_COUNT_SIZE(U_OFFSET), bus->u);
	SetUInt(data + UINT_COUNT_SIZE(N_OFFSET), bus->n);
	SetUInt(data + UINT_COUNT_SIZE(T_OFFSET), bus->t);
	SetUInt(data + UINT_COUNT_SIZE(V_OFFSET), bus->v);
	SetUInt(data + UINT_COUNT_SIZE(S_OFFSET), bus->s);
	SetUInt(data + UINT_COUNT_SIZE(A_OFFSET), bus->a);
	SetUInt(data + UINT_COUNT_SIZE(M_OFFSET), bus->m);
	SetUInt(data + UINT_COUNT_SIZE(O_OFFSET), bus->o);

	return S_OK;
}



static_inline HRESULT BusProtocol_Get(unsigned char* data, BusProtocol* bus) {

	rc_assert(data != NULL, E_FAIL)
	rc_assert(bus != NULL, E_FAIL)

	GetUInt(data + UINT_COUNT_SIZE(U_OFFSET), &bus->u);
	GetUInt(data + UINT_COUNT_SIZE(N_OFFSET), &bus->n);
	GetUInt(data + UINT_COUNT_SIZE(T_OFFSET), &bus->t);
	GetUInt(data + UINT_COUNT_SIZE(V_OFFSET), &bus->v);
	GetUInt(data + UINT_COUNT_SIZE(S_OFFSET), &bus->s);
	GetUInt(data + UINT_COUNT_SIZE(A_OFFSET), &bus->a);
	GetUInt(data + UINT_COUNT_SIZE(M_OFFSET), &bus->m);
	GetUInt(data + UINT_COUNT_SIZE(O_OFFSET), &bus->o);

	return S_OK;
}

static_inline HRESULT BusProtocol_SetValue(unsigned char* data, int offset, unsigned int value) {

	rc_assert(data != NULL, E_FAIL)

	SetUInt(data + UINT_COUNT_SIZE(offset), value);

	return S_OK;
}

static_inline HRESULT BusProtocol_GetValue(unsigned char* data, int offset, unsigned int* value) {

	rc_assert(data != NULL, E_FAIL)
	rc_assert(value != NULL, E_FAIL)

	GetUInt(data + UINT_COUNT_SIZE(offset), value);

	return S_OK;
}

static_inline HRESULT BusProtocol_Init_Head(unsigned char* data,
	unsigned int uid,
	unsigned int netmask,
	unsigned int ver,
	unsigned int type) {

	rc_assert(data != NULL, E_FAIL)
	s_memset(data, 0, BUS_PROTOCOL_HEAD_LEN);

	HRESULT hr = S_OK;

	hr = BusProtocol_SetValue(data, U_OFFSET, uid);
	rc_assert(hr == S_OK, E_FAIL)

	hr = BusProtocol_SetValue(data, N_OFFSET, netmask);
	rc_assert(hr == S_OK, E_FAIL)

	hr = BusProtocol_SetValue(data, T_OFFSET, type);
	rc_assert(hr == S_OK, E_FAIL)

	hr = BusProtocol_SetValue(data, V_OFFSET, ver);
	rc_assert(hr == S_OK, E_FAIL)

	return S_OK;
}


static_inline HRESULT BusProtocol_Get_Seq_Ack(unsigned char* ptr, unsigned int* seq, unsigned int* ack) {

	rc_assert(ptr != NULL, E_FAIL)

	HRESULT hr = S_OK;

	hr = BusProtocol_GetValue(ptr, S_OFFSET, seq);
	rc_assert(hr == S_OK, E_FAIL)

	hr = BusProtocol_GetValue(ptr, A_OFFSET, ack);
	rc_assert(hr == S_OK, E_FAIL)

	return S_OK;
}

static_inline HRESULT BusProtocol_1st(unsigned char* ptr, unsigned int seq, unsigned int ack) {

	rc_assert(ptr != NULL, E_FAIL)

	HRESULT hr = S_OK;

	hr = BusProtocol_SetValue(ptr, S_OFFSET, seq);
	rc_assert(hr == S_OK, E_FAIL)

	hr = BusProtocol_SetValue(ptr, A_OFFSET, ack);
	rc_assert(hr == S_OK, E_FAIL)


	return S_OK;
}

static_inline HRESULT BusProtocol_2nd(unsigned char* ptr, unsigned int seq, unsigned int ack) {

	rc_assert(ptr != NULL, E_FAIL)

	HRESULT hr = S_OK;

	hr = BusProtocol_SetValue(ptr, A_OFFSET, seq + 1);
	rc_assert(hr == S_OK, E_FAIL)

	hr = BusProtocol_SetValue(ptr, S_OFFSET, ack);
	rc_assert(hr == S_OK, E_FAIL)

	return S_OK;
}

static_inline HRESULT BusProtocol_3rd(unsigned char* ptr, unsigned int seq, unsigned int ack) {

	rc_assert(ptr != NULL, E_FAIL)

	HRESULT hr = S_OK;

	hr = BusProtocol_SetValue(ptr, S_OFFSET, seq + 1);
	rc_assert(hr == S_OK, E_FAIL)

	hr = BusProtocol_SetValue(ptr, A_OFFSET, ack);
	rc_assert(hr == S_OK, E_FAIL)

	return S_OK;
}



#endif
